#include "imgui_manager.h"
#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"
//#include "imgui_impl_opengl2.h"
#include "implot.h"
#include "implot3d.h"
#include <GLFW/glfw3.h>
#include <iostream>

GLFWwindow *window = nullptr;

void SetupImGui()
{
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImPlot::CreateContext();
    ImPlot3D::CreateContext();

    ImGuiIO &io = ImGui::GetIO();
    (void)io;
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
#ifdef ImGuiConfigFlags_ViewportsEnable
    io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
#endif

    ImGui::StyleColorsDark();

    if (!ImGui_ImplGlfw_InitForOpenGL(window, true))
    {
        std::cerr << "[ERROR] ImGui_ImplGlfw_InitForOpenGL failed" << std::endl;
        std::abort();
    }
    if (!ImGui_ImplOpenGL3_Init())
    {
        std::cerr << "[ERROR] ImGui_ImplOpenGL2_Init failed" << std::endl;
        std::abort();
    }

    std::cerr << "[INFO] ImGui and ImPlot initialized with OpenGL2 backend." << std::endl;
}

void CleanupImGui()
{
    ImGui_ImplOpenGL3_Shutdown();
    ImGui_ImplGlfw_Shutdown();
    ImPlot::DestroyContext();
    ImPlot3D::DestroyContext();
    ImGui::DestroyContext();
}

CustomControl ::~CustomControl() {}

void CustomControl::setShow(std::function<void()> _func)
{
    this->show = _func;
}

void CustomControl::Show()
{
    this->show();
}

void ImGuiManager::Init(int _width, int _height)
{
    this->width = _width;
    this->height = _height;
}

void ImGuiManager::AddControl(std::shared_ptr<Control> control)
{
    controls.push_back(control);
}

void ImGuiManager::Show()
{
    ImGui_ImplOpenGL3_NewFrame();
    ImGui_ImplGlfw_NewFrame();
    ImGui::NewFrame();

    for (auto &control : controls)
    {
        control->Show();
    }

    ImGui::Render();
    int display_w, display_h;
    glfwGetFramebufferSize(window, &display_w, &display_h);
    glViewport(0, 0, display_w, display_h);
    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

    glfwSwapBuffers(window);
}

void ImGuiManager::Run()
{
    running = true;
    renderThread = std::thread(
        [this]()
        {
            if (!glfwInit())
            {
                std::cerr << "[ERROR] Failed to initialize GLFW" << std::endl;
                std::abort();
            }

            const char *glsl_version = nullptr;

#if defined(IMGUI_IMPL_OPENGL_ES2)
            glsl_version = "#version 100";
            glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
            glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
            glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
#elif defined(IMGUI_IMPL_OPENGL_ES3)
            glsl_version = "#version 300 es";
            glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
            glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
            glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
#elif defined(__APPLE__)
            glsl_version = "#version 150";
            glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
            glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
            glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
            glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#else
            glsl_version = "#version 130";
            glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
            glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
#endif

            window = glfwCreateWindow(width, height, "ImGui Manager", nullptr, nullptr);
            if (!window)
            {
                std::cerr << "[ERROR] Failed to create GLFW window" << std::endl;
                glfwTerminate();
                std::abort();
            }

            glfwMakeContextCurrent(window);
            glfwSwapInterval(1); // Enable vsync

            std::cerr << "[INFO] GLFW and OpenGL context successfully created" << std::endl;
            SetupImGui();

            while (!glfwWindowShouldClose(window) && running)
            {
                glfwPollEvents();

                for (auto &func : timeFunc)
                {
                    func();
                }

                Show();

                // sImGui_ImplGlfw_Sleep(66);
            }

            CleanupImGui();
            glfwDestroyWindow(window);
            glfwTerminate();
        });
    renderThread.detach();
}

void ImGuiManager::addTimeFunc(std::function<void()> _func)
{
    this->timeFunc.push_back(_func);
}